/*
 * QIconAdapter.cpp  0.4.0 / Nov 17, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "QIconAdapter.h"

#include "SwingImageDelegate.h"

// QIconAdapter :: Public Constructors. ----------------------------------------

/*!
 * \brief Constructs new QIconAdapter object.
 *
 * \param env the JNIEnv pointer
 * \param iconSet the icon set object
 */
QIconAdapter::QIconAdapter(JNIEnv *env, jobject iconSet)
  : QIcon(new QIconAdapterEngine(env, iconSet))
{
  // empty constructor body
}

/*!
 * \brief Constructs new QIconAdapter object.
 *
 * \param env the JNIEnv pointer
 * \param iconSet the icon set object
 * \param m_iconType the icon type pointer
 */
QIconAdapter::QIconAdapter(JNIEnv *env, jobject iconSet, IconType *m_iconType)
  : QIcon(new QIconAdapterEngine(env, iconSet, m_iconType))
{
  // empty constructor body
}

// QIconAdapterEngine :: Public Constructors. ----------------------------------

/*!
 * \brief Constructs new QIconAdapterEngine object.
 *
 * \param env the JNIEnv pointer
 * \param iconSet the icon set
 */
QIconAdapterEngine::QIconAdapterEngine(JNIEnv *env, jobject iconSet)
  : m_iconSet(JNISwingWrapper::newGlobalRef(iconSet)), m_iconType(0), 
    m_makeDisabledIcon(true), m_disabledIconGenerated(false)
{
  Q_UNUSED(env);
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
  for (int i = QIconAdapter::DefaultIcon;
       i <= QIconAdapter::RolloverSelectedIcon; i++) {
    m_icons[i] = 0;
  }
  JNISwingWrapper::setLongField(m_iconSet, sm_iconEnginePointerFID,
                                reinterpret_cast<jlong>(this));
}

/*!
 * \brief Constructs new QIconAdapterEngine object.
 *
 * \param env the JNIEnv pointer
 * \param iconSet the icon set
 * \param m_iconType the icon type pointer
 */
QIconAdapterEngine::QIconAdapterEngine(JNIEnv *env, jobject iconSet,
                                       QIconAdapter::IconType *m_iconType)
  : m_iconSet(JNISwingWrapper::newGlobalRef(iconSet)), m_iconType(m_iconType), 
    m_makeDisabledIcon(true), m_disabledIconGenerated(false)
{
  Q_UNUSED(env);
  Q_ASSERT(JNISwingWrapper::isSwingThread(env));
  for (int i = QIconAdapter::DefaultIcon;
       i <= QIconAdapter::RolloverSelectedIcon; i++) {
    m_icons[i] = 0;
  }
  JNISwingWrapper::setLongField(m_iconSet, sm_iconEnginePointerFID,
                                reinterpret_cast<jlong>(this));
}

// QIconAdapterEngine :: Public Destructor. ------------------------------------

/*!
 * \brief Destroys the QIconAdapterEngine object.
 */
QIconAdapterEngine::~QIconAdapterEngine() {
  if (m_iconSet) {
    JNISwingWrapper::setLongField(m_iconSet, sm_iconEnginePointerFID, 0);
    JNISwingWrapper::deleteGlobalRef(m_iconSet);
  }
  if (m_disabledIconGenerated) {
    delete m_icons[QIconAdapter::DisabledIcon];
  }
}

// QIconAdapterEngine :: Public Member Functions. ------------------------------

/*!
 * \brief Sets default icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setIcon(QPixmap *image)
{
  if (m_disabledIconGenerated) {
    delete m_icons[QIconAdapter::DisabledIcon];
    m_disabledIconGenerated = false;
    m_makeDisabledIcon = true;
  }
  for (int i = QIconAdapter::PressedIcon;
       i <= QIconAdapter::RolloverSelectedIcon; i++) {
    if (m_icons[i] == m_icons[QIconAdapter::DefaultIcon]) {
      m_icons[i] = image;
    }
  }
  m_icons[QIconAdapter::DefaultIcon] = image;
}

/*!
 * \brief Sets pressed icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setPressedIcon(QPixmap *image)
{
  m_icons[QIconAdapter::PressedIcon] = image;
}

/*!
 * \brief Removes pressed icon.
 */
void QIconAdapterEngine::removePressedIcon()
{
  m_icons[QIconAdapter::PressedIcon] = m_icons[QIconAdapter::DefaultIcon];
}

/*!
 * \brief Sets selected icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setSelectedIcon(QPixmap *image)
{
  m_icons[QIconAdapter::SelectedIcon] = image;
  m_icons[QIconAdapter::RolloverSelectedIcon] = image;
}

/*!
 * \brief Removes selected icon.
 */
void QIconAdapterEngine::removeSelectedIcon()
{
  m_icons[QIconAdapter::SelectedIcon] = m_icons[QIconAdapter::DefaultIcon];
  if (m_icons[QIconAdapter::SelectedIcon] ==
      m_icons[QIconAdapter::RolloverSelectedIcon]) {
    m_icons[QIconAdapter::RolloverSelectedIcon] =
                                            m_icons[QIconAdapter::DefaultIcon];
  }
}

/*!
 * \brief Sets disabled icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setDisabledIcon(QPixmap *image)
{
  if (m_disabledIconGenerated) {
    delete m_icons[QIconAdapter::DisabledIcon];
    m_disabledIconGenerated = false;
  }
  QPixmap *oldDisabledIcon = m_icons[QIconAdapter::DisabledIcon];
  m_icons[QIconAdapter::DisabledIcon] = image;
  if (m_icons[QIconAdapter::DisabledSelectedIcon] == oldDisabledIcon) {
    m_icons[QIconAdapter::DisabledSelectedIcon] = image;
  }
  m_makeDisabledIcon = false;
}

/*!
 * \brief Removes disabled icon.
 */
void QIconAdapterEngine::removeDisabledIcon()
{
  m_icons[QIconAdapter::DisabledIcon] = 0;
  m_makeDisabledIcon = true;
}

/*!
 * \brief Sets disabled selected icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setDisabledSelectedIcon(QPixmap *image)
{
  m_icons[QIconAdapter::DisabledSelectedIcon] = image;
}

/*!
 * \brief Removes disabled selected icon.
 */
void QIconAdapterEngine::removeDisabledSelectedIcon()
{
  m_icons[QIconAdapter::DisabledSelectedIcon] =
                                           m_icons[QIconAdapter::DisabledIcon];
}

/*!
 * \brief Sets rollover icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setRolloverIcon(QPixmap *image)
{
  m_icons[QIconAdapter::RolloverIcon] = image;
}

/*!
 * \brief Removes rollover icon.
 */
void QIconAdapterEngine::removeRolloverIcon()
{
  m_icons[QIconAdapter::RolloverIcon] = m_icons[QIconAdapter::DefaultIcon];
}

/*!
 * \brief Sets rollover selected icon.
 *
 * \param image the icon image
 */
void QIconAdapterEngine::setRolloverSelectedIcon(QPixmap *image)
{
  m_icons[QIconAdapter::RolloverSelectedIcon] = image;
}

/*!
 * \brief Removes rollover selected icon.
 */
void QIconAdapterEngine::removeRolloverSelectedIcon()
{
  m_icons[QIconAdapter::RolloverSelectedIcon] =
                                            m_icons[QIconAdapter::DefaultIcon];
}

// QIconAdapterEngine :: Overridden Member Functions. --------------------------

/*!
 * \inheritDoc
 */
QPixmap QIconAdapterEngine::pixmap(const QSize &size, QIcon::Mode mode,
                                   QIcon::State state)
{
  Q_UNUSED(size);
  int type = iconType(mode, state);
  if (m_icons[type]) {
    return *m_icons[type];
  } else {
    int width = getWidth(type);
    int height = getHeight(type);
    if ((width > 0) && (height > 0)) {
      QSize pixmapSize(width, height);
      QPixmap pixmap(pixmapSize);
      QBitmap bitmapMask(pixmapSize);
      bitmapMask.clear();
      pixmap.setMask(bitmapMask);
      SwingGraphics graphics(&pixmap, 0, 0, width, height);
      JNISwingWrapper::callVoidMethod(m_iconSet, sm_paintIconMID,
                                      reinterpret_cast<jlong>(&graphics), type);
      return pixmap;
    } else {
      return QPixmap();
    }
  }
}

/*!
 * \inheritDoc
 */
QSize QIconAdapterEngine::actualSize(const QSize &size, QIcon::Mode mode,
                                     QIcon::State state)
{
  Q_UNUSED(size);
  int type = iconType(mode, state);
  QPixmap *pixmap = m_icons[type];
  if (pixmap) {
    return pixmap->size();
  } else {
    return QSize(getWidth(type), getHeight(type));
  }
}

/*!
 * \inheritDoc
 */
void QIconAdapterEngine::paint(QPainter *painter, const QRect &rect,
                               QIcon::Mode mode, QIcon::State state)
{
  int type = iconType(mode, state);
  QPixmap *pixmap = m_icons[type];
  if (pixmap) {
    painter->drawPixmap(rect, *pixmap);
  } else {
    int width = getWidth(type);
    int height = getHeight(type);
    if ((width > 0) && (height > 0)) {
      QSize pixmapSize(width, height);
      QPixmap pixmap(pixmapSize);
      QBitmap bitmapMask(pixmapSize);
      bitmapMask.clear();
      pixmap.setMask(bitmapMask);
      SwingGraphics graphics(&pixmap, 0, 0, width, height);
      JNISwingWrapper::callVoidMethod(m_iconSet, sm_paintIconMID,
                                      reinterpret_cast<jlong>(&graphics), type);
      painter->drawPixmap(rect, pixmap);
    }
  }
}

/*!
 * \inheritDoc
 */
void QIconAdapterEngine::addFile(const QString &str, const QSize &size,
                                 QIcon::Mode mode, QIcon::State state)
{
  Q_UNUSED(str);
  Q_UNUSED(size);
  Q_UNUSED(mode);
  Q_UNUSED(state);
  // empty method body
}

/*!
 * \inheritDoc
 */
void QIconAdapterEngine::addPixmap(const QPixmap &pm, QIcon::Mode mode,
                                   QIcon::State state)
{
  Q_UNUSED(pm);
  Q_UNUSED(mode);
  Q_UNUSED(state);
  // empty method body
}

// QIconAdapterEngine :: Public Static Member Function. ------------------------

/*!
 * \brief Initializes QIconAdapterEngine class.
 *
 * \param env the JNIEnv pointer 
 * \param cls the SwingIconSet class
 */
void QIconAdapterEngine::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_iconEnginePointerFID);
  if (!INIT_UFID(iconEnginePointer, cls, "J") ||
      !INIT_UMID(getIconWidth, cls, "(I)I") ||
      !INIT_UMID(getIconHeight, cls, "(I)I") ||
      !INIT_UMID(paintIcon, cls, "(JI)V")) {
    FATAL_LOGGED_ERROR("QIconAdapterEngine initialization failed");
  }
}

// QIconAdapterEngine :: Private Member Functions. -----------------------------

QIconAdapter::IconType QIconAdapterEngine::iconType(QIcon::Mode mode,
                                                    QIcon::State state)
{
  if (m_iconType != 0) {
    if ((*m_iconType == QIconAdapter::DisabledIcon) && m_makeDisabledIcon) {
      makeDisabledIcon();
    }
    return *m_iconType;
  }
  switch ((state << 2) | mode) {
    case 0:  // mode="Normal" state="On"
      return QIconAdapter::SelectedIcon;
    case 1:  // mode="Disabled" state="On"
      return QIconAdapter::DisabledSelectedIcon;
    case 2:  // mode="Active" state="On"
      return QIconAdapter::RolloverSelectedIcon;
    case 3:  // mode="Selected" state="On"
      return QIconAdapter::SelectedIcon;
    case 4:  // mode="Normal" state="Off"
      return QIconAdapter::DefaultIcon;
    case 5:  // mode="Disabled" state="Off"
      if (m_makeDisabledIcon) {
        makeDisabledIcon();
      }
      return QIconAdapter::DisabledIcon;
    case 6:  // mode="Active" state="Off"
      return QIconAdapter::RolloverIcon;
    case 7:  // mode="Selected" state="Off"
      return QIconAdapter::SelectedIcon;
    default:
      return QIconAdapter::DefaultIcon;
  }
}

void QIconAdapterEngine::makeDisabledIcon()
{
  m_makeDisabledIcon = false;
  QPixmap *oldDisabledIcon = m_icons[QIconAdapter::DisabledIcon];
  m_icons[QIconAdapter::DisabledIcon] =
        SwingImageDelegate::createDisabledPixmap(
                                           m_icons[QIconAdapter::DefaultIcon]);
  m_disabledIconGenerated = (m_icons[QIconAdapter::DisabledIcon] != 0);
  if ((m_icons[QIconAdapter::DisabledSelectedIcon] == oldDisabledIcon) ||
      (m_icons[QIconAdapter::DisabledSelectedIcon] ==
                                          m_icons[QIconAdapter::DefaultIcon])) {
    m_icons[QIconAdapter::DisabledSelectedIcon] =
                                            m_icons[QIconAdapter::DisabledIcon];
  }
}

jint QIconAdapterEngine::getWidth(jint type)
{
  jint width;
  if (JNISwingWrapper::callIntMethod(width, m_iconSet, sm_getIconWidthMID,
                                     type)) {
    return width;
  }
  return 0;
}

jint QIconAdapterEngine::getHeight(jint type)
{
  jint height;
  if (JNISwingWrapper::callIntMethod(height, m_iconSet, sm_getIconHeightMID,
                                     type)) {
    return height;
  }
  return 0;
}

// QIconAdapterEngine :: Private Static Data Members. --------------------------

jfieldID QIconAdapterEngine::sm_iconEnginePointerFID = 0;
jmethodID QIconAdapterEngine::sm_getIconWidthMID = 0;
jmethodID QIconAdapterEngine::sm_getIconHeightMID = 0;
jmethodID QIconAdapterEngine::sm_paintIconMID = 0;

